# import unsloth
# import torch
# import torch.nn as nn
# import torch.nn.functional as F
# import math
# from modelscope import AutoTokenizer, AutoModelForCausalLM, snapshot_download
# from unsloth import FastLanguageModel
# # 设置pip国内镜像源（推荐清华源）
# import os
#
# max_seq_length = 2048
# dtype = None
# load_in_4bit = True
#
# model_name = "unsloth/Qwen3-0.6B"
# model_dir = snapshot_download(model_name)
#
# model, tokenizer = FastLanguageModel.from_pretrained(
#     model_dir,
#     max_seq_length=max_seq_length,
#     dtype=dtype,
#     load_in_4bit=load_in_4bit,
# )
#
# prompt_style = """以下是描述任务的指令，以及提供进一步上下文的输入。
# 请写出一个适当完成请求的回答。
# 在回答之前，请仔细思考问题，并创建一个逻辑连贯的思考过程，以确保回答准确无误。
#
# ### 指令：
# 你是一位精通卜卦、星象和运势预测的算命大师。
# 请回答以下算命问题。
#
# ### 问题：
# {}
#
# ### 回答：
# <think>{}"""
# # 定义提示风格的字符串模板，用于格式化问题
#
# question = "1992年闰四月初九巳时生人，女，想了解健康运势"
# # 定义具体的算命问题
#
# FastLanguageModel.for_inference(model)
# # 准备模型以进行推理
#
# inputs = tokenizer([prompt_style.format(question, "")], return_tensors="pt").to("cuda")
# # 使用 tokenizer 对格式化后的问题进行编码，并移动到 GPU
#
# outputs = model.generate(
#     input_ids=inputs.input_ids,
#     attention_mask=inputs.attention_mask,
#     max_new_tokens=1200,
#     use_cache=True,
# )
# # 使用模型生成回答
#
# response = tokenizer.batch_decode(outputs)
# # 解码模型生成的输出为可读文本
#
# print(response[0])
#
#
# # 定义一个用于格式化提示的多行字符串模板
# train_prompt_style = """以下是描述任务的指令，以及提供进一步上下文的输入。
# 请写出一个适当完成请求的回答。
# 在回答之前，请仔细思考问题，并创建一个逻辑连贯的思考过程，以确保回答准确无误。
#
# ### 指令：
# 你是一位精通八字算命、 紫微斗数、 风水、易经卦象、塔罗牌占卜、星象、面相手相和运势预测等方面的算命大师。
# 请回答以下算命问题。
#
# ### 问题：
# {}
#
# ### 回答：
# <思考>
# {}
# </思考>
# {}"""
#
# EOS_TOKEN = tokenizer.eos_token  # 必须添加结束标记
# from modelscope.msdatasets import MsDataset
# dataset_name = 'AI-ModelScope/fortune-telling'
# dataset = MsDataset.load(dataset_name, trust_remote_code=True, subset_name="default", split="train")
# # 定义一个函数，用于格式化数据集中的每条记录
# def formatting_prompts_func(examples):
#     # 从数据集中提取问题、复杂思考过程和回答
#     inputs = examples["Question"]
#     cots = examples["Complex_CoT"]
#     outputs = examples["Response"]
#     texts = []  # 用于存储格式化后的文本
#     # 遍历每个问题、思考过程和回答，进行格式化
#     for input, cot, output in zip(inputs, cots, outputs):
#         # 使用字符串模板插入数据，并加上结束标记
#         text = train_prompt_style.format(input, cot, output) + EOS_TOKEN
#         texts.append(text)  # 将格式化后的文本添加到列表中
#     return {
#         "text": texts,  # 返回包含所有格式化文本的字典
#     }
#
# dataset = dataset.map(formatting_prompts_func, batched = True)
# dataset["text"][0]
#
# FastLanguageModel.for_training(model)
#
# model = FastLanguageModel.get_peft_model(
#     model,  # 传入已经加载好的预训练模型
#     r = 16,  # 设置 LoRA 的秩，决定添加的可训练参数数量
#     target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",  # 指定模型中需要微调的关键模块
#                       "gate_proj", "up_proj", "down_proj"],
#     lora_alpha = 16,  # 设置 LoRA 的超参数，影响可训练参数的训练方式
#     lora_dropout = 0,  # 设置防止过拟合的参数，这里设置为 0 表示不丢弃任何参数
#     bias = "none",    # 设置是否添加偏置项，这里设置为 "none" 表示不添加
#     use_gradient_checkpointing = "unsloth",  # 使用优化技术节省显存并支持更大的批量大小
#     random_state = 3407,  # 设置随机种子，确保每次运行代码时模型的初始化方式相同
#     use_rslora = False,  # 设置是否使用 Rank Stabilized LoRA 技术，这里设置为 False 表示不使用
#     loftq_config = None,  # 设置是否使用 LoftQ 技术，这里设置为 None 表示不使用
# )
#
# from trl import SFTTrainer  # 导入 SFTTrainer，用于监督式微调
# from transformers import TrainingArguments  # 导入 TrainingArguments，用于设置训练参数
# from unsloth import is_bfloat16_supported  # 导入函数，检查是否支持 bfloat16 数据格式
#
# trainer = SFTTrainer(  # 创建一个 SFTTrainer 实例
#     model=model,  # 传入要微调的模型
#     tokenizer=tokenizer,  # 传入 tokenizer，用于处理文本数据
#     train_dataset=dataset,  # 传入训练数据集
#     dataset_text_field="text",  # 指定数据集中文本字段的名称
#     max_seq_length=max_seq_length,  # 设置最大序列长度
#     dataset_num_proc=1,  # 设置数据处理的并行进程数
#     packing=False,  # 是否启用打包功能（这里设置为 False，打包可以让训练更快，但可能影响效果）
#     args=TrainingArguments(  # 定义训练参数
#         per_device_train_batch_size=2,  # 每个设备（如 GPU）上的批量大小
#         gradient_accumulation_steps=4,  # 梯度累积步数，用于模拟大批次训练
#         warmup_steps=5,  # 预热步数，训练开始时学习率逐渐增加的步数
#         max_steps=75,  # 最大训练步数
#         learning_rate=2e-4,  # 学习率，模型学习新知识的速度
#         fp16=not is_bfloat16_supported(),  # 是否使用 fp16 格式加速训练（如果环境不支持 bfloat16）
#         bf16=is_bfloat16_supported(),  # 是否使用 bfloat16 格式加速训练（如果环境支持）
#         logging_steps=1,  # 每隔多少步记录一次训练日志
#         optim="adamw_8bit",  # 使用的优化器，用于调整模型参数
#         weight_decay=0.01,  # 权重衰减，防止模型过拟合
#         lr_scheduler_type="linear",  # 学习率调度器类型，控制学习率的变化方式
#         seed=3407,  # 随机种子，确保训练结果可复现
#         output_dir="outputs",  # 训练结果保存的目录
#         report_to="none",  # 是否将训练结果报告到外部工具（如 WandB），这里设置为不报告
#     ),
# )
#
# trainer_stats = trainer.train()
#
# print(question) # 打印前面的问题
# # 将模型切换到推理模式，准备回答问题
# FastLanguageModel.for_inference(model)
#
# # 将问题转换成模型能理解的格式，并发送到 GPU 上
# inputs = tokenizer([prompt_style.format(question, "")], return_tensors="pt").to("cuda")
#
# # 让模型根据问题生成回答，最多生成 4000 个新词
# outputs = model.generate(
#     input_ids=inputs.input_ids,  # 输入的数字序列
#     attention_mask=inputs.attention_mask,  # 注意力遮罩，帮助模型理解哪些部分重要
#     max_new_tokens=40000,  # 最多生成 4000 个新词
#     use_cache=True,  # 使用缓存加速生成
# )
#
# # 将生成的回答从数字转换回文字
# response = tokenizer.batch_decode(outputs)
#
# # 打印回答
# print(response[0])